/*
 * SDIR.H
 *
 * Colorful, sorted and optionally rich directory enumeration
 * for Windows.
 *
 * Copyright (c) 2014-16 Malcolm J. Smith
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif

#ifndef FKG_FORCED_USAGE
#define FKG_FORCED_USAGE 1
#endif

#if SDIR_FEATURE_LEVEL >= 4
#define SDIR_SUPPORT_VT 1
#endif

#if SDIR_FEATURE_LEVEL >= 3
#define SDIR_SUPPORT_RECURSIVE 1
#define SDIR_SUPPORT_LONGPATH 1
#define SDIR_SUPPORT_CUSTOM_METACOLOR 1
#endif

#if SDIR_FEATURE_LEVEL >= 2
#define SDIR_SUPPORT_STREAMENUM 1
#define SDIR_SUPPORT_CUSTOM_FILECOLOR 1
#endif

#include <windows.h>
#include <winioctl.h>
#ifndef MINICRT
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#endif
#include <tchar.h>

#ifdef MINICRT
#include <minicrt.h>
#endif


//
//  Compile time configuration
//

#define SDIR_MAX_WIDTH   500

#define SDIR_DEFAULT_COLOR        (FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE)
#define SDIR_FUTURE_VERSION_COLOR (FOREGROUND_RED|FOREGROUND_INTENSITY)

//
//  Hacks for older compilers
//

#if (defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1310)
#pragma comment(linker, "/OPT:NOWIN98")
#endif

#ifdef _ULONGLONG_
#define SDIR_BIG_SIZE 1
typedef ULONGLONG SDIR_FILESIZE;
#define SdirFileSizeFromLargeInt(Li) ((Li)->QuadPart)
#elif !defined(_MSC_VER) || _MSC_VER >= 900
#define SDIR_BIG_SIZE 1
typedef LONGLONG SDIR_FILESIZE;
#define SdirFileSizeFromLargeInt(Li) ((Li)->QuadPart)
#else
#pragma message("64 bit file size support not present")
typedef ULONG SDIR_FILESIZE;
#define SdirFileSizeFromLargeInt(Li) ((Li)->LowPart)
#endif

#ifndef FILE_SHARE_DELETE
#define FILE_SHARE_DELETE 4
#endif

#ifndef FILE_ATTRIBUTE_SPARSE_FILE
#define FILE_ATTRIBUTE_SPARSE_FILE        (0x200)
#endif

#ifndef FILE_ATTRIBUTE_REPARSE_POINT
#define FILE_ATTRIBUTE_REPARSE_POINT      (0x400)
#endif

#ifndef FILE_ATTRIBUTE_COMPRESSED
#define FILE_ATTRIBUTE_COMPRESSED         (0x800)
#endif

#ifndef FILE_ATTRIBUTE_OFFLINE
#define FILE_ATTRIBUTE_OFFLINE           (0x1000)
#endif

#ifndef FILE_ATTRIBUTE_ENCRYPTED
#define FILE_ATTRIBUTE_ENCRYPTED         (0x4000)
#endif

#ifndef FILE_ATTRIBUTE_INTEGRITY_STREAM
#define FILE_ATTRIBUTE_INTEGRITY_STREAM  (0x8000)
#endif

#ifndef FILE_FLAG_OPEN_REPARSE_POINT
#define FILE_FLAG_OPEN_REPARSE_POINT     (0x00200000)
#endif

#ifndef FILE_FLAG_OPEN_NO_RECALL
#define FILE_FLAG_OPEN_NO_RECALL         (0x00100000)
#endif

#ifndef FSCTL_GET_COMPRESSION
#define FSCTL_GET_COMPRESSION           CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define COMPRESSION_FORMAT_NONE         (0x0000)
#define COMPRESSION_FORMAT_LZNT1        (0x0002)
#endif

#ifndef FSCTL_GET_RETRIEVAL_POINTERS
#define FSCTL_GET_RETRIEVAL_POINTERS     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 28,  METHOD_NEITHER, FILE_ANY_ACCESS)

typedef struct {

    LARGE_INTEGER StartingVcn;

} STARTING_VCN_INPUT_BUFFER, *PSTARTING_VCN_INPUT_BUFFER;

typedef struct RETRIEVAL_POINTERS_BUFFER {

    DWORD ExtentCount;
    LARGE_INTEGER StartingVcn;
    struct {
        LARGE_INTEGER NextVcn;
        LARGE_INTEGER Lcn;
    } Extents[1];

} RETRIEVAL_POINTERS_BUFFER, *PRETRIEVAL_POINTERS_BUFFER;
#endif

#ifndef FSCTL_QUERY_ALLOCATED_RANGES
#define FSCTL_QUERY_ALLOCATED_RANGES    CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51,  METHOD_NEITHER, FILE_READ_DATA)

typedef struct _FILE_ALLOCATED_RANGE_BUFFER {

    LARGE_INTEGER FileOffset;
    LARGE_INTEGER Length;

} FILE_ALLOCATED_RANGE_BUFFER, *PFILE_ALLOCATED_RANGE_BUFFER;

#endif

#ifndef FSCTL_GET_OBJECT_ID
#define FSCTL_GET_OBJECT_ID             CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 39, METHOD_BUFFERED, FILE_ANY_ACCESS)

typedef struct _FILE_OBJECTID_BUFFER {

    BYTE  ObjectId[16];

    BYTE  ExtendedInfo[48];

} FILE_OBJECTID_BUFFER, *PFILE_OBJECTID_BUFFER;
#endif

#ifndef FSCTL_READ_FILE_USN_DATA
#define FSCTL_READ_FILE_USN_DATA         CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 58,  METHOD_NEITHER, FILE_ANY_ACCESS)
#endif

#ifndef FSCTL_GET_EXTERNAL_BACKING
#define FSCTL_GET_EXTERNAL_BACKING       CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 196, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif

#ifndef WOF_PROVIDER_WIM

#define WOF_PROVIDER_WIM                 (0x0001)

typedef struct _WOF_EXTERNAL_INFO {
    DWORD Version;
    DWORD Provider;
} WOF_EXTERNAL_INFO, *PWOF_EXTERNAL_INFO;

#define WIM_PROVIDER_HASH_SIZE           20

typedef struct _WIM_PROVIDER_EXTERNAL_INFO {
    DWORD Version;
    DWORD Flags;
    LARGE_INTEGER DataSourceId;
    BYTE  ResourceHash[WIM_PROVIDER_HASH_SIZE];
} WIM_PROVIDER_EXTERNAL_INFO, *PWIM_PROVIDER_EXTERNAL_INFO;
#endif

#ifndef WOF_PROVIDER_FILE
#define WOF_PROVIDER_FILE                   (0x0002)
#define FILE_PROVIDER_COMPRESSION_XPRESS4K  (0x0000)
#define FILE_PROVIDER_COMPRESSION_LZX       (0x0001)
#define FILE_PROVIDER_COMPRESSION_XPRESS8K  (0x0002)
#define FILE_PROVIDER_COMPRESSION_XPRESS16K (0x0003)

typedef struct _FILE_PROVIDER_EXTERNAL_INFO {
    DWORD Version;
    DWORD Algorithm;
    DWORD Flags;
} FILE_PROVIDER_EXTERNAL_INFO, *PFILE_PROVIDER_EXTERNAL_INFO;

#endif

//
//  These were added in Vista but because they're not preprocessor
//  they're very hard to test for, so we test for something else
//

#ifndef GetFinalPathNameByHandle
typedef struct _FILE_STANDARD_INFO {
    LARGE_INTEGER AllocationSize;
    LARGE_INTEGER EndOfFile;
    DWORD NumberOfLinks;
    BOOLEAN DeletePending;
    BOOLEAN Directory;
} FILE_STANDARD_INFO, *PFILE_STANDARD_INFO;

#define FileStandardInfo    (0x000000001)
#endif

#ifndef IO_REPARSE_TAG_SYMLINK
#define IO_REPARSE_TAG_SYMLINK                  (0xA000000CL)
#endif

#ifndef IO_REPARSE_TAG_MOUNT_POINT
#define IO_REPARSE_TAG_MOUNT_POINT              (0xA0000003L)
#endif

#ifndef IMAGE_FILE_MACHINE_AMD64
#define IMAGE_FILE_MACHINE_AMD64   0x8664
#endif

#ifndef IMAGE_FILE_MACHINE_ARMNT
#define IMAGE_FILE_MACHINE_ARMNT   0x01c4
#endif

#ifndef IMAGE_FILE_MACHINE_ARM64
#define IMAGE_FILE_MACHINE_ARM64   0xAA64
#endif

#ifndef IMAGE_SUBSYSTEM_NATIVE_WINDOWS
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8
#endif

#ifndef IMAGE_SUBSYSTEM_WINDOWS_CE_GUI
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9
#endif

#ifndef IMAGE_SUBSYSTEM_EFI_APPLICATION
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
#endif

#ifndef IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
#endif

#ifndef IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
#endif

#ifndef IMAGE_SUBSYSTEM_EFI_ROM
#define IMAGE_SUBSYSTEM_EFI_ROM 13
#endif

#ifndef IMAGE_SUBSYSTEM_XBOX
#define IMAGE_SUBSYSTEM_XBOX 14
#endif

#ifndef IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION
#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16
#endif

#ifndef IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG
#define IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG 17
#endif

#ifndef TRUSTEE_IS_SID

#define TRUSTEE_IS_SID  0
#define TRUSTEE_IS_USER 1

typedef struct _TRUSTEE {
    PVOID Ignored1;
    ULONG Ignored2;
    ULONG TrusteeForm;
    ULONG TrusteeType;
    LPTSTR ptstrName;
} TRUSTEE, *PTRUSTEE;

#endif

#ifndef _stprintf_s
#define _stprintf_s _sntprintf
#endif

#ifndef _tcstok_s
#define _tcstok_s(a,b,c) _tcstok(a,b)
#endif

#ifndef __in
#define __in
#define __out
#define __out_opt
#define __inout
#define __in_ecount(x)
#define __out_ecount(x)
#pragma warning(disable: 4068) // unknown pragma
#endif

//
//  File size lengths
//

//  This is from WIN32_FIND_STREAM_DATA
#define SDIR_MAX_STREAM_NAME          (MAX_PATH + 36)
//  This is from WIN32_FIND_DATA.  Actually a little large, and
//  ends up being truncated a couple characters
#define SDIR_MAX_FILE_NAME            (MAX_PATH)
#define SDIR_MAX_FILE_AND_STREAM_NAME (SDIR_MAX_FILE_NAME + SDIR_MAX_STREAM_NAME)

typedef struct {

    DWORD          RecordLength;
    WORD           MajorVersion;
    WORD           MinorVersion;
    DWORDLONG      FileReferenceNumber;
    DWORDLONG      ParentFileReferenceNumber;
    LARGE_INTEGER  Usn;
    LARGE_INTEGER  TimeStamp;
    DWORD          Reason;
    DWORD          SourceInfo;
    DWORD          SecurityId;
    DWORD          FileAttributes;
    WORD           FileNameLength;
    WORD           FileNameOffset;
    WCHAR          FileName[1];

} SDIR_USN_RECORD, *PSDIR_USN_RECORD;

typedef struct _SDIR_WIN32_FIND_STREAM_DATA {
    LARGE_INTEGER StreamSize;
    WCHAR cStreamName[SDIR_MAX_STREAM_NAME];
} SDIR_WIN32_FIND_STREAM_DATA, *PSDIR_WIN32_FIND_STREAM_DATA;

typedef struct _SDIR_ATTRPAIR {
    DWORD FileAttribute;
    TCHAR DisplayLetter;
} SDIR_ATTRPAIR, *PSDIR_ATTRPAIR;

extern const SDIR_ATTRPAIR AttrPairs[];

//
//  Run time configuration data
//

typedef struct _SDIR_FMTCHAR {
    TCHAR Char;
    WORD  Attr;
} SDIR_FMTCHAR, *PSDIR_FMTCHAR;

#define SDIR_ATTRIBUTE_INVERT           0x100
#define SDIR_ATTRIBUTE_HIDE             0x200
#define SDIR_ATTRIBUTE_CONTINUE         0x400
#define SDIR_ATTRIBUTE_FILE             0x800
#define SDIR_ATTRIBUTE_FULLCOLOR_MASK   0xFF
#define SDIR_ATTRIBUTE_ONECOLOR_MASK    0x0F
#define SDIR_ATTRIBUTE_TERMINATE_MASK   (SDIR_ATTRIBUTE_FULLCOLOR_MASK|SDIR_ATTRIBUTE_HIDE)

#define SDIR_ATTRIBUTE_INVALID_METADATA ~(SDIR_ATTRIBUTE_FULLCOLOR_MASK|SDIR_ATTRIBUTE_FILE)
#define SDIR_ATTRIBUTE_INVALID_FILE     ~(SDIR_ATTRIBUTE_FULLCOLOR_MASK|SDIR_ATTRIBUTE_INVERT|SDIR_ATTRIBUTE_HIDE|SDIR_ATTRIBUTE_CONTINUE)

typedef struct _SDIR_ATTRIBUTE_COLOR_STRING {
    LPTSTR String;
    WORD Attribute;
} SDIR_ATTRIBUTE_COLOR_STRING, *PSDIR_ATTRIBUTE_COLOR_STRING;

extern SDIR_ATTRIBUTE_COLOR_STRING ColorString[];

//
// This order corresponds to sort order
//

enum {
    SdirCompressionNone = 0,
    SdirCompressionWofFileUnknown,
    SdirCompressionLznt,
    SdirCompressionLzx,
    SdirCompressionNtfsUnknown,
    SdirCompressionWim,
    SdirCompressionWofUnknown,
    SdirCompressionXpress4k,
    SdirCompressionXpress8k,
    SdirCompressionXpress16k
} SdirCompressionAlgorithms;

#define SDIR_COMPRESSION_ALGORITHM_LZNT   1
#define SDIR_COMPRESSION_ALGORITHM_NTFS   2
#define SDIR_COMPRESSION_ALGORITHM_WIM    3
#define SDIR_COMPRESSION_ALGORITHM_LZX    4

typedef struct _SDIR_DIRENT {
    LARGE_INTEGER FileId;
    LARGE_INTEGER AllocationSize;
    LARGE_INTEGER FileSize;
    LARGE_INTEGER CompressedFileSize;
    LARGE_INTEGER Usn;
    LARGE_INTEGER FileVersion;
    DWORD         FileVersionFlags;
    WORD          OsVersionHigh;
    WORD          OsVersionLow;
    SYSTEMTIME    AccessTime;
    SYSTEMTIME    CreateTime;
    SYSTEMTIME    WriteTime;
    BYTE          ObjectId[16];
    DWORD         LinkCount;
    DWORD         StreamCount;
    DWORD         ReparseTag;
    DWORD         FileAttributes;
    DWORD         CompressionAlgorithm;
    LARGE_INTEGER FragmentCount;
    LARGE_INTEGER AllocatedRangeCount;
    ACCESS_MASK   EffectivePermissions;
    WORD          RenderAttributes;
    WORD          Architecture;
    WORD          Subsystem;
    TCHAR         Owner[17];
    DWORD         FileNameLengthInChars;
    TCHAR         ShortFileName[14];
    TCHAR         FileName[SDIR_MAX_FILE_NAME]; // Should really be SDIR_MAX_FILE_AND_STREAM_NAME
    TCHAR *       Extension;
} SDIR_DIRENT, *PSDIR_DIRENT;

typedef BOOL (WINAPI * DISABLE_WOW_REDIRECT_FN)(PVOID*);
typedef HANDLE (WINAPI * FIND_FIRST_STREAM_FN)(LPCTSTR, DWORD, PSDIR_WIN32_FIND_STREAM_DATA, DWORD);
typedef BOOL (WINAPI * FIND_NEXT_STREAM_FN)(HANDLE, PSDIR_WIN32_FIND_STREAM_DATA);
typedef DWORD (WINAPI * GET_COMPRESSED_FILE_SIZE_FN)(LPCTSTR, LPDWORD);
typedef BOOL (WINAPI * GET_DISK_FREE_SPACE_EX_FN)(LPCTSTR, PLARGE_INTEGER, PLARGE_INTEGER, PLARGE_INTEGER);
typedef BOOL (WINAPI * GET_FILE_INFORMATION_BY_HANDLE_EX_FN)(HANDLE, ULONG, PVOID, DWORD);

typedef DWORD (* SDIR_METADATA_WIDTH_FN)(PSDIR_FMTCHAR, WORD, PSDIR_DIRENT);
typedef DWORD (* SDIR_COMPARE_FN)(PSDIR_DIRENT, PSDIR_DIRENT);
typedef BOOL (* SDIR_COLLECT_FN)(PSDIR_DIRENT, PWIN32_FIND_DATA, LPCTSTR);
typedef BOOL (* SDIR_GENERATE_FROM_STRING_FN)(PSDIR_DIRENT, LPCTSTR);

typedef struct _SDIR_COMPARE {
    SDIR_COMPARE_FN CompareFn;
    DWORD           CompareBreakCondition;
    DWORD           CompareInverseCondition;
} SDIR_COMPARE, *PSDIR_COMPARE;


#define SDIR_FEATURE_COLLECT              (0x01)
#define SDIR_FEATURE_DISPLAY              (0x02)
#define SDIR_FEATURE_ALLOW_DISPLAY        (0x04)
#define SDIR_FEATURE_ALLOW_SORT           (0x08)
#define SDIR_FEATURE_FIXED_COLOR          (0x10)
#define SDIR_FEATURE_USE_FILE_COLOR       (0x20)

typedef struct _SDIR_FEATURE {
    WORD Flags;
    WORD HighlightColor;
} SDIR_FEATURE, *PSDIR_FEATURE;

typedef struct _SDIR_OPTS {
    LPTSTR          CustomFileColor;
    DWORD           CustomFileColorLength;

    LPTSTR          CustomFileFilter;
    DWORD           CustomFileFilterLength;

    LPTSTR          SubDirWalk;

    LPTSTR          ParentName;
    DWORD           ParentNameLength;

    SDIR_FILESIZE   BriefRecurseSize;
    DWORD           BriefRecurseDepth;
    DWORD           ConsoleHeight;
    DWORD           ConsoleBufferWidth;
    DWORD           ConsoleWidth;
    DWORD           MetadataWidth;
    DWORD           OsVersion;

    SDIR_FEATURE    FtAccessDate;
    SDIR_FEATURE    FtAccessTime;
    SDIR_FEATURE    FtAllocatedRangeCount;
    SDIR_FEATURE    FtAllocationSize;
    SDIR_FEATURE    FtArch;
    SDIR_FEATURE    FtBriefAlternate;
    SDIR_FEATURE    FtCompressionAlgorithm;
    SDIR_FEATURE    FtCompressedFileSize;
    SDIR_FEATURE    FtCreateDate;
    SDIR_FEATURE    FtCreateTime;
    SDIR_FEATURE    FtError;
    SDIR_FEATURE    FtEffectivePermissions;
    SDIR_FEATURE    FtFileAttributes;
    SDIR_FEATURE    FtFileExtension;
    SDIR_FEATURE    FtFileId;
    SDIR_FEATURE    FtFileName;
    SDIR_FEATURE    FtFileSize;
    SDIR_FEATURE    FtFragmentCount;
    SDIR_FEATURE    FtGrid;
    SDIR_FEATURE    FtLinkCount;
    SDIR_FEATURE    FtNamedStreams;
    SDIR_FEATURE    FtNumberFiles;
    SDIR_FEATURE    FtObjectId;
    SDIR_FEATURE    FtOsVersion;
    SDIR_FEATURE    FtOwner;
    SDIR_FEATURE    FtReparseTag;
    SDIR_FEATURE    FtShortName;
    SDIR_FEATURE    FtStreamCount;
    SDIR_FEATURE    FtSubsystem;
    SDIR_FEATURE    FtSummary;
    SDIR_FEATURE    FtUsn;
    SDIR_FEATURE    FtVersion;
    SDIR_FEATURE    FtWriteDate;
    SDIR_FEATURE    FtWriteTime;

    BOOLEAN         EnablePause:1;
    BOOLEAN         EnableNameTruncation:1;
    BOOLEAN         OutputWithConsoleApi:1;
    BOOLEAN         OutputIsUnicode:1;
    BOOLEAN         Cancelled:1;
    BOOLEAN         ErrorsFound:1;
    BOOLEAN         TraverseLinks:1;

    BOOLEAN         OutputVt100Color:1;
    BOOLEAN         OutputHasAutoLineWrap:1;
    BOOLEAN         OutputExtendedCharacters:1;

    WORD            PreviousAttributes;
    TCHAR           PathPrefixChar;

    LPTSTR          NewLine;

    DWORD           CurrentSort;
    SDIR_COMPARE    Sort[8];

    FIND_FIRST_STREAM_FN                 FindFirstStreamW;
    FIND_NEXT_STREAM_FN                  FindNextStreamW;
    GET_COMPRESSED_FILE_SIZE_FN          GetCompressedFileSize;
    GET_DISK_FREE_SPACE_EX_FN            GetDiskFreeSpaceEx;
    GET_FILE_INFORMATION_BY_HANDLE_EX_FN GetFileInformationByHandleEx;

} SDIR_OPTS, *PSDIR_OPTS;

typedef struct _SDIR_SUMMARY {
    ULONG           NumFiles;
    ULONG           NumDirs;
    SDIR_FILESIZE   TotalSize;
    SDIR_FILESIZE   CompressedSize;
    LARGE_INTEGER   FreeSize;
    LARGE_INTEGER   VolumeSize;
} SDIR_SUMMARY, *PSDIR_SUMMARY;

typedef struct _SDIR_OPT {
    DWORD                        FtOffset;
    TCHAR                        Switch[3];
    SDIR_FEATURE                 Default;
    SDIR_METADATA_WIDTH_FN       WidthFn;
    SDIR_COLLECT_FN              CollectFn;
    SDIR_COMPARE_FN              CompareFn;
    SDIR_COMPARE_FN              BitwiseCompareFn;
    SDIR_GENERATE_FROM_STRING_FN GenerateFromStringFn;
    CHAR                         Help[24];
} SDIR_OPT, *PSDIR_OPT;

#define SDIR_LESS_THAN    0
#define SDIR_EQUAL        1
#define SDIR_GREATER_THAN 2

#define SDIR_NOT_EQUAL    0

typedef struct _SDIR_EXEC {
    DWORD FtOffset;
    SDIR_METADATA_WIDTH_FN Function;
} SDIR_EXEC, *PSDIR_EXEC;

extern PSDIR_OPTS Opts;
extern PSDIR_SUMMARY Summary;
extern const SDIR_OPT SdirOptions[];
extern const SDIR_EXEC SdirExec[];
extern const CHAR SdirAttributeDefaultApplyString[];

//
//  Functions from display.c
//

BOOL
SdirWriteRawStringToOutputDevice(
    __in HANDLE hConsole,
    __in LPCTSTR OutputString,
    __in DWORD Length
    );

BOOL
SdirSetConsoleTextAttribute(
    __in HANDLE hConsole,
    __in WORD Attribute
    );

BOOL
SdirGetConsoleScreenBufferInfo(
    __in HANDLE hConsole,
    __out PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo
    );

BOOL
SdirQueryVtSupport();

BOOL
SdirWrite (
    __in_ecount(count) PSDIR_FMTCHAR str,
    __in DWORD count
    );

BOOL
SdirPasteStrAndPad (
    __out_ecount(padsize) PSDIR_FMTCHAR str,
    __in_ecount(count) LPTSTR src,
    __in WORD attr,
    __in DWORD count,
    __in DWORD padsize
    );

BOOL
SdirPressAnyKey ();

BOOL
SdirRowDisplayed();

BOOL
SdirWriteStringWithAttribute (
    __in LPCTSTR str,
    __in WORD DefaultAttribute
    );

BOOL
SdirDisplayError (
    __in LONG ErrorCode,
    __in LPCTSTR Prefix
    );


#define SdirWriteString(str) SdirWriteStringWithAttribute(str, SDIR_DEFAULT_COLOR)

#define SdirPasteStr(str, src, attr, count) \
    SdirPasteStrAndPad(str, src, attr, count, count)

//
//  Functions from callbacks.c
//

DWORD
SdirGetNumSdirOptions();

DWORD
SdirGetNumSdirExec();

ULONG
SdirDisplaySummary(
    __in WORD DefaultAttributes
    );

BOOL
SdirCollectSummary(
    __in PSDIR_DIRENT Entry
    );

ULONG
SdirDisplayShortName (
    PSDIR_FMTCHAR Buffer,
    __in WORD Attributes,
    __in PSDIR_DIRENT Entry
    );

DWORD
SdirCompareFileName (
    __in PSDIR_DIRENT Left,
    __in PSDIR_DIRENT Right
    );

#define SdirFeatureByOptionNumber(OPTNUM) \
    (PSDIR_FEATURE)((PUCHAR)Opts + SdirOptions[(OPTNUM)].FtOffset)

//
//  Functions from color.c
//

BOOL
SdirColorStringFromFeature(
    __in PSDIR_FEATURE Feature,
    __out LPTSTR String,
    __in DWORD StringSize
    );

BOOL
SdirParseAttributeApplyString();

BOOL
SdirParseMetadataAttributeString();

BOOL
SdirApplyAttribute(
    __in PSDIR_DIRENT DirEnt,
    __out WORD *Attribute
    );

//
//  Functions from init.c
//

BOOL
SdirInit(
    __in int argc,
    __in_ecount(argc) LPTSTR argv[]
    );

//
//  Functions from sdir.c
//

DWORD
SdirGetNumAttrPairs();

//
//  Functions from usage.c
//

BOOL
SdirUsage(
    __in int argc,
    __in_ecount(argc) LPTSTR argv[]
    );

//
//  Functions from utils.c
//

DWORD
SdirCompareLargeInt (
    __in PULARGE_INTEGER Left,
    __in PULARGE_INTEGER Right
    );

DWORD
SdirCompareString (
    __in LPCTSTR Left,
    __in LPCTSTR Right
    );

DWORD
SdirCompareDate (
    __in LPSYSTEMTIME Left,
    __in LPSYSTEMTIME Right
    );

DWORD
SdirCompareTime (
    __in LPSYSTEMTIME Left,
    __in LPSYSTEMTIME Right
    );

DWORD
SdirStringToNum32(
    __in LPCTSTR str,
    __out_opt LPCTSTR* endptr
    );

LARGE_INTEGER
SdirStringToNum64(
    __in LPCTSTR str,
    __out_opt LPCTSTR* endptr
    );

BOOL
SdirStringToHexBuffer(
    __in LPCTSTR str,
    __out PUCHAR buffer,
    __in DWORD size,
    __out_opt LPCTSTR* endptr
    );

LARGE_INTEGER
SdirStringToFileSize(
    __in LPCTSTR str
    );

BOOL
SdirStringToDate(
    __in LPCTSTR str,
    __out LPSYSTEMTIME date
    );

BOOL
SdirStringToTime(
    __in LPCTSTR str,
    __out LPSYSTEMTIME date
    );

ULONG
SdirDisplayGenericSize(
    __out_ecount(6) PSDIR_FMTCHAR Buffer,
    __in WORD Attributes,
    __in PLARGE_INTEGER GenericSize
    );

ULONG
SdirDisplayHex64 (
    __out_ecount(18) PSDIR_FMTCHAR Buffer,
    __in WORD Attributes,
    __in PLARGE_INTEGER Hex
    );

ULONG
SdirDisplayHex32 (
    __out_ecount(9) PSDIR_FMTCHAR Buffer,
    __in WORD Attributes,
    __in DWORD Hex
    );

ULONG
SdirDisplayGenericHexBuffer (
    __out_ecount(Size * 2 + 1) PSDIR_FMTCHAR Buffer,
    __in WORD Attributes,
    __in PUCHAR InputBuffer,
    __in DWORD Size
    );

ULONG
SdirDisplayFileDate (
    __out_ecount(11) PSDIR_FMTCHAR Buffer,
    __in WORD Attributes,
    __in SYSTEMTIME * Time
    );

ULONG
SdirDisplayFileTime (
    __out_ecount(9) PSDIR_FMTCHAR Buffer,
    __in WORD Attributes,
    __in SYSTEMTIME * Time
    );

#define SdirAnsiToUnicode(u, l, a) _stprintf_s(u, l, _T("%hs"), a)

BOOL
SdirIsFullPathUnc(
    __in LPCTSTR szPath
    );

DWORD
SdirGetFullPathName(
    __in LPCTSTR szFileName,
    __in DWORD nBufferLength,
    __out LPTSTR lpBuffer,
    __out_opt LPTSTR* lpFilePart
    );

BOOL
SdirGetFullPathNameReturnAllocation(
    __in LPCTSTR szFileName,
    __out LPTSTR* lpBuffer,
    __out_opt LPTSTR* lpFilePart
    );

// vim:sw=4:ts=4:et:
